package cleaner

import (
	"file-cleaner/internal/file_cleaner/file_info"
	"file-cleaner/internal/file_cleaner/queue"
	v1log "github.com/ClessLi/component-base/pkg/log/v1"
	"strings"
	"time"
)

type fileInfoHashMap map[string]*file_info.FileInfo

type sizeMap map[int64]fileInfoHashMap

type deviceMap map[uint64]sizeMap

type FileCleaner struct {
	queryQueue     queue.Queue
	cleanTaskQueue queue.Queue
	hashMap        deviceMap
}

func NewFileCleaner(queryQueue queue.Queue, cleanTaskQueue queue.Queue) *FileCleaner {
	return &FileCleaner{
		queryQueue:     queryQueue,
		cleanTaskQueue: cleanTaskQueue,
		hashMap:        make(deviceMap),
	}
}

func (c *FileCleaner) Run() {
	for {
		n := c.queryQueue.Size()
		for i := 0; i < n; i++ {
			if c.queryQueue.IsEmpty() {
				break
			}
			item := c.queryQueue.Poll()
			if item == queue.Done {
				c.cleanTaskQueue.Add(item)
				return
			}
			info, ok := item.(*file_info.FileInfo)
			if ok {
				c.publishCleanTask(info)
			} else {
				v1log.Errorf("info(%v) type(%T) is not FileInfo", item, item)
			}
		}
		time.Sleep(time.Millisecond)
	}
}

func (c *FileCleaner) publishCleanTask(info *file_info.FileInfo) {
	if len(strings.TrimSpace(info.Hash())) == 0 {
		v1log.Errorf("Failed to publish clean task, cased by: no hash for %v", info.Path())
		return
	}

	c.cleanTaskQueue.Add(NewCleanTaskInfo(info, c.getTargetFileInfo(info)))
}

func (c *FileCleaner) getTargetFileInfo(info *file_info.FileInfo) *file_info.FileInfo {
	d, s, h := info.DevNum(), info.Size(), info.Hash()

	dev, hasDev := c.hashMap[d]
	if !hasDev {
		dev = make(sizeMap)
		c.hashMap[d] = dev
	}

	size, hasSize := dev[s]
	if !hasSize {
		size = make(fileInfoHashMap)
		dev[s] = size
	}

	targetInfo, hasInfo := size[h]
	if !hasInfo {
		targetInfo = info.Copy()
		size[h] = targetInfo
	}

	return targetInfo
}
